﻿using System;
using Microsoft.Practices.ServiceLocation;
using Mockery.Core.CommonContainer;
using Rhino.Mocks;

namespace Mockery.Core
{
    /// <summary>
    /// This is the class that creates a mockery instance by declaring the intended type
    /// </summary>
    public static class InjectedTest
    {
        /// <summary>
        /// Create a mockery around the class under test with the opportunity to run
        /// a delegate at the beginning of the test
        /// </summary>
        /// <typeparam name="TTypeUnderTest">class under test</typeparam>
        /// <returns>mockery strong-typed on the class under test</returns>
        public static Mockery<TTypeUnderTest> Target<TTypeUnderTest>(Action<TTypeUnderTest> actStep) where TTypeUnderTest : class
        {
            return CreateMockery(actStep);
        }


        /// <summary>
        /// Create a mockery around the class-under-test 
        /// </summary>
        /// <typeparam name="TTypeUnderTest">class under test</typeparam>
        /// <returns>mockery strong-typed on the class under test</returns>
        public static Mockery<TTypeUnderTest> Target<TTypeUnderTest>() where TTypeUnderTest : class
        {
            return CreateMockery<TTypeUnderTest>(null);
        }


        private static Mockery<TTypeUnderTest> CreateMockery<TTypeUnderTest>(Action<TTypeUnderTest> actStep) where TTypeUnderTest : class
        {
            var containerBuilder = CommonContainerLocator.CreateBuilder();

            containerBuilder.RegisterType<TTypeUnderTest, TTypeUnderTest>();

            containerBuilder.RegisterType<Arrangement, IArrangement>();
            containerBuilder.RegisterType<Mockery<TTypeUnderTest>>();
            containerBuilder.RegisterType<MockRepository>();
            containerBuilder.RegisterType<Arranger, IArranger>();
            containerBuilder.RegisterType<TypeCache, ITypeCache>();
            containerBuilder.RegisterType<ActiveMockeryState, IActiveMockeryState>();
            containerBuilder.RegisterType<RepositoryStateHandler, IRepositoryStateHandler>();
            containerBuilder.RegisterType<DisposableContextState, IDisposableContextState>();
            containerBuilder.RegisterInstance(typeof (ICommonContainerBuilder), CommonContainerLocator.CreateBuilder());

            
            IServiceLocator serviceLocator;

            if (actStep == null)
            {
                containerBuilder.RegisterType<MockeryStateEvents, IMockeryStateEvents>();
                serviceLocator = containerBuilder.ServiceLocator;
            }
            else
            {
                containerBuilder.RegisterType<DeclarativeMockeryStateEvents<TTypeUnderTest>, IMockeryStateEvents>();
                serviceLocator = containerBuilder.ServiceLocator;

                ((DeclarativeMockeryStateEvents<TTypeUnderTest>)serviceLocator.GetInstance<IMockeryStateEvents>()).
                    ActionDelegate = actStep;
            }
            
            return serviceLocator.GetInstance<Mockery<TTypeUnderTest>>();
        }
    }
}
